#ifndef DEBUGGERDRIVER_H
#define DEBUGGERDRIVER_H

#include "debugger_defs.h"
#include <wx/regex.h>
#include <globals.h>

#define NOT_IMPLEMENTED()   \
  do {                    \
    DebugLog(wxString(cbC2U(__PRETTY_FUNCTION__)) + _T(": Not implemented in driver"));     \
    Log(wxString(cbC2U(__PRETTY_FUNCTION__)) + _T(": Not implemented in driver"));           \
  } while(0)

class DebuggerGDB;
class Compiler;
class ProjectBuildTarget;

WX_DEFINE_ARRAY( DebuggerCmd*, DebuggerCommands );

class DebuggerDriver {
  public:
    enum QueuePriority {
      Low = 0,
      High
    };
    typedef std::vector<cb::shared_ptr<cbStackFrame> > StackFrameContainer;
    typedef std::vector<cb::shared_ptr<cbThread> > ThreadsContainer;
    DebuggerDriver( DebuggerGDB* plugin );
    virtual ~DebuggerDriver();
    void Log( const wxString& msg );
    void DebugLog( const wxString& msg );
    DebuggerGDB* GetDebugger() { return m_pDBG; }
    virtual void AddDirectory( const wxString& dir );
    virtual void ClearDirectories();
    virtual void SetWorkingDirectory( const wxString& dir );
    virtual void SetArguments( const wxString& args );
    virtual wxString GetCommandLine( const wxString& debugger, const wxString& debuggee,
                                     const wxString &userArguments ) = 0;
    virtual wxString GetCommandLine( const wxString& debugger, int pid, const wxString &userArguments ) = 0;
    virtual void SetTarget( ProjectBuildTarget* target ) = 0;
    virtual void Prepare( bool isConsole, int printElements ) = 0;
    virtual void Start( bool breakOnEntry ) = 0;
    virtual void Stop() = 0;
    virtual void Continue() = 0;
    virtual void Step() = 0;
    virtual void StepInstruction() = 0;
    virtual void StepIntoInstruction() = 0;
    virtual void StepIn() = 0;
    virtual void StepOut() = 0;
    virtual void SetNextStatement( const wxString& filename, int line ) = 0;
    virtual void Backtrace() = 0;
    virtual void Disassemble() = 0;
    virtual void CPURegisters() = 0;
    virtual void SwitchToFrame( size_t number ) = 0;
    virtual void SetVarValue( const wxString& var, const wxString& value ) = 0;
    virtual void MemoryDump() = 0;
    virtual void RunningThreads() = 0;
    virtual void InfoFrame() = 0;
    virtual void InfoDLL() = 0;
    virtual void InfoFiles() = 0;
    virtual void InfoFPU() = 0;
    virtual void InfoSignals() = 0;
    virtual void EnableCatchingThrow( bool enable ) = 0;
    virtual void AddBreakpoint( cb::shared_ptr<DebuggerBreakpoint> bp ) = 0;
    virtual void RemoveBreakpoint( cb::shared_ptr<DebuggerBreakpoint> bp ) = 0;
    virtual void EvaluateSymbol( const wxString& symbol, const wxRect& tipRect ) = 0;
    virtual void UpdateWatches( cb::shared_ptr<GDBWatch> localsWatch, cb::shared_ptr<GDBWatch> funcArgsWatch,
                                WatchesContainer &watches ) = 0;
    virtual void UpdateWatch( cb::shared_ptr<GDBWatch> const &watch ) = 0;
    virtual void UpdateWatchLocalsArgs( cb::shared_ptr<GDBWatch> const &watch, bool locals ) = 0;
    virtual void Attach( int pid ) = 0;
    virtual void Detach() = 0;
    virtual void ParseOutput( const wxString& output ) = 0;
    virtual bool IsDebuggingStarted() const = 0;
    bool IsProgramStopped() const { return m_ProgramIsStopped; }
    void MarkProgramStopped( bool stopped ) { m_ProgramIsStopped = stopped; }
    bool IsQueueBusy() const { return m_QueueBusy; }
    void SetChildPID( long pid ) { m_ChildPID = pid; }
    long GetChildPID() const { return m_ChildPID; }
    virtual void SwitchThread( size_t threadIndex ) = 0;
    wxString GetDebuggersWorkingDirectory() const;
    void ShowFile( const wxString& file, int line );
    void QueueCommand( DebuggerCmd* dcmd, QueuePriority prio = Low );
    DebuggerCmd* CurrentCommand();
    void RunQueue();
    void RemoveTopCommand( bool deleteIt = true );
    const StackFrameContainer & GetStackFrames() const;
    StackFrameContainer & GetStackFrames();
    const ThreadsContainer & GetThreads() const;
    ThreadsContainer & GetThreads();
    const Cursor& GetCursor() const { return m_Cursor; }
    void SetCursor( const Cursor& cursor ) { m_Cursor = cursor; }
    void ResetCurrentFrame();
    int GetCurrentFrame() const { return m_currentFrameNo; }
    int GetUserSelectedFrame() const { return m_userSelectedFrameNo; }
    void SetCurrentFrame( int number, bool user_selected );
    void NotifyDebuggeeContinued();
    void NotifyCursorChanged();
  protected:
    void ResetCursor();
  protected:
    DebuggerGDB* m_pDBG;
    wxArrayString m_Dirs;
    wxString m_WorkingDir;
    wxString m_Args;
    bool m_ProgramIsStopped;
    wxString m_LastCursorAddress;
    Cursor m_Cursor;
    long m_ChildPID;
    DebuggerCommands m_DCmds;
    bool m_QueueBusy;
    StackFrameContainer m_backtrace;
    ThreadsContainer m_threads;
    int m_currentFrameNo;
    int m_userSelectedFrameNo;
};

#endif
